home *** CD-ROM | disk | FTP | other *** search
/ Clickx 115 / Clickx 115.iso / software / tools / windows / tails-i386-0.16.iso / live / filesystem.squashfs / usr / bin / system-config-printer-applet < prev    next >
Encoding:
Text File  |  2010-09-28  |  15.0 KB  |  432 lines

  1. #!/usr/bin/env python
  2.  
  3. ## Copyright (C) 2007, 2008, 2009, 2010 Red Hat, Inc.
  4. ## Author: Tim Waugh <twaugh@redhat.com>
  5.  
  6. ## This program is free software; you can redistribute it and/or modify
  7. ## it under the terms of the GNU General Public License as published by
  8. ## the Free Software Foundation; either version 2 of the License, or
  9. ## (at your option) any later version.
  10.  
  11. ## This program is distributed in the hope that it will be useful,
  12. ## but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. ## GNU General Public License for more details.
  15.  
  16. ## You should have received a copy of the GNU General Public License
  17. ## along with this program; if not, write to the Free Software
  18. ## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  
  20. import cups
  21. cups.require ("1.9.42")
  22. import sys
  23. sys.path.append("/usr/share/system-config-printer")
  24. from debug import *
  25.  
  26. import dbus
  27. import dbus.glib
  28. import dbus.service
  29. import gobject
  30. import pynotify
  31. import time
  32. import locale
  33. import gettext
  34. import installdriver
  35. from gettext import gettext as _
  36. DOMAIN="system-config-printer"
  37. gettext.textdomain (DOMAIN)
  38. try:
  39.     locale.setlocale (locale.LC_ALL, "")
  40. except locale.Error, e:
  41.     import os
  42.     os.environ['LC_ALL'] = 'C'
  43.     locale.setlocale (locale.LC_ALL, "")
  44.  
  45. APPDIR="/usr/share/system-config-printer"
  46. DOMAIN="system-config-printer"
  47. ICON="printer"
  48. SEARCHING_ICON="document-print-preview"
  49.  
  50. # Let gobject know we'll be using threads.
  51. gobject.threads_init ()
  52.  
  53. # We need to call pynotify.init before we can check the server for caps
  54. pynotify.init('System Config Printer Notification')
  55.  
  56. ####
  57. #### NewPrinterNotification DBus server (the 'new' way).
  58. ####
  59. PDS_PATH="/com/redhat/NewPrinterNotification"
  60. PDS_IFACE="com.redhat.NewPrinterNotification"
  61. PDS_OBJ="com.redhat.NewPrinterNotification"
  62. class NewPrinterNotification(dbus.service.Object):
  63.     STATUS_SUCCESS = 0
  64.     STATUS_MODEL_MISMATCH = 1
  65.     STATUS_GENERIC_DRIVER = 2
  66.     STATUS_NO_DRIVER = 3
  67.  
  68.     def __init__ (self, bus):
  69.         self.bus = bus
  70.         self.getting_ready = 0
  71.         bus_name = dbus.service.BusName (PDS_OBJ, bus=bus)
  72.         dbus.service.Object.__init__ (self, bus_name, PDS_PATH)
  73.  
  74.     def wake_up (self):
  75.         global waitloop, runloop, viewer
  76.         import jobviewer
  77.         if viewer == None:
  78.             try:
  79.                 waitloop.quit ()
  80.             except:
  81.                 pass
  82.             runloop = gobject.MainLoop ()
  83.             viewer = jobviewer.JobViewer(bus=bus, loop=runloop,
  84.                                          trayicon=trayicon,
  85.                                          suppress_icon_hide=True)
  86.  
  87.     @dbus.service.method(PDS_IFACE, in_signature='', out_signature='')
  88.     def GetReady (self):
  89.         self.wake_up ()
  90.         if self.getting_ready == 0:
  91.             viewer.set_special_statusicon (SEARCHING_ICON,
  92.                                            tooltip=_("Configuring new printer"))
  93.  
  94.         self.getting_ready += 1
  95.         gobject.timeout_add_seconds (1200, self.timeout_ready)
  96.  
  97.     def timeout_ready (self):
  98.         global viewer
  99.         if self.getting_ready > 0:
  100.             self.getting_ready -= 1
  101.         if self.getting_ready == 0:
  102.             viewer.unset_special_statusicon ()
  103.  
  104.         return False
  105.  
  106.     @dbus.service.method(PDS_IFACE, in_signature='isssss', out_signature='')
  107.     def NewPrinter (self, status, name, mfg, mdl, des, cmd):
  108.         global viewer
  109.         self.wake_up ()
  110.  
  111.         if name.find("/") >= 0:
  112.             # name is a URI, no queue was generated, because no suitable
  113.             # driver was found
  114.             title = _("Missing printer driver")
  115.             devid = "MFG:%s;MDL:%s;DES:%s;CMD:%s;" % (mfg, mdl, des, cmd)
  116.             if (mfg and mdl) or des:
  117.                 if (mfg and mdl):
  118.                     device = "%s %s" % (mfg, mdl)
  119.                 else:
  120.                     device = des
  121.                 text = _("No printer driver for %s.") % device
  122.             else:
  123.                 text = _("No driver for this printer.")
  124.             n = pynotify.Notification (title, text, 'printer')
  125.             if "actions" in pynotify.get_server_caps():
  126.                 n.set_urgency (pynotify.URGENCY_CRITICAL)
  127.                 n.set_timeout (pynotify.EXPIRES_NEVER)
  128.                 n.add_action ("setup-printer", _("Search"),
  129.                               lambda x, y:
  130.                                   self.setup_printer (x, y, name, devid))
  131.             else:
  132.                 args = ["--setup-printer", name, "--devid", devid]
  133.                 self.run_config_tool (args)
  134.  
  135.         else:
  136.             # name is the name of the queue which hal_lpadmin has set up
  137.             # automatically.
  138.             c = cups.Connection ()
  139.             try:
  140.                 printer = c.getPrinters ()[name]
  141.             except KeyError:
  142.                 return
  143.  
  144.             try:
  145.                 filename = c.getPPD (name)
  146.             except cups.IPPError:
  147.                 return
  148.  
  149.             del c
  150.  
  151.             # Check for missing packages
  152.             cups.ppdSetConformance (cups.PPD_CONFORM_RELAXED)
  153.             ppd = cups.PPD (filename)
  154.             import os
  155.             os.unlink (filename)
  156.             import sys
  157.             sys.path.append (APPDIR)
  158.             import cupshelpers
  159.             (missing_pkgs,
  160.              missing_exes) = cupshelpers.missingPackagesAndExecutables (ppd)
  161.  
  162.             from cupshelpers.ppds import ppdMakeModelSplit
  163.             (make, model) = ppdMakeModelSplit (printer['printer-make-and-model'])
  164.             driver = make + " " + model
  165.             if status < self.STATUS_GENERIC_DRIVER:
  166.                 title = _("Printer added")
  167.             else:
  168.                 title = _("Missing printer driver")
  169.  
  170.             if len (missing_pkgs) > 0:
  171.                 pkgs = reduce (lambda x,y: x + ", " + y, missing_pkgs)
  172.                 title = _("Install printer driver")
  173.                 text = _("`%s' requires driver installation: %s.") % (name, pkgs)
  174.                 n = pynotify.Notification (title, text)
  175.                 import installpackage
  176.                 if "actions" in pynotify.get_server_caps():
  177.                     try:
  178.                         self.packagekit = installpackage.PackageKit ()
  179.                         n.set_timeout (pynotify.EXPIRES_NEVER)
  180.                         n.add_action ("install-driver", _("Install"),
  181.                                       lambda x, y:
  182.                                           self.install_driver (x, y,
  183.                                                                missing_pkgs))
  184.                     except:
  185.                         pass
  186.                 else:
  187.                     try:
  188.                         self.packagekit = installpackage.PackageKit ()
  189.                         self.packagekit.InstallPackageName (0, 0,
  190.                                                             missing_pkgs[0])
  191.                     except:
  192.                         pass
  193.  
  194.             elif status == self.STATUS_SUCCESS:
  195.                 devid = "MFG:%s;MDL:%s;DES:%s;CMD:%s;" % (mfg, mdl, des, cmd)
  196.                 text = _("`%s' is ready for printing.") % name
  197.                 n = pynotify.Notification (title, text)
  198.                 if "actions" in pynotify.get_server_caps():
  199.                     n.set_urgency (pynotify.URGENCY_NORMAL)
  200.                     n.add_action ("test-page", _("Print test page"),
  201.                                   lambda x, y:
  202.                                       self.print_test_page (x, y, name, devid))
  203.                     n.add_action ("configure", _("Configure"),
  204.                                   lambda x, y: self.configure (x, y, name))
  205.             else: # Model mismatch
  206.                 devid = "MFG:%s;MDL:%s;DES:%s;CMD:%s;" % (mfg, mdl, des, cmd)
  207.                 text = (_("`%s' has been added, using the `%s' driver.") %
  208.                         (name, driver))
  209.                 n = pynotify.Notification (title, text, 'printer')
  210.                 if "actions" in pynotify.get_server_caps():
  211.                     n.set_urgency (pynotify.URGENCY_CRITICAL)
  212.                     n.add_action ("test-page", _("Print test page"),
  213.                                   lambda x, y:
  214.                                       self.print_test_page (x, y, name, devid))
  215.                     n.add_action ("find-driver", _("Find driver"),
  216.                                   lambda x, y: 
  217.                                   self.find_driver (x, y, name, devid))
  218.                     n.set_timeout (pynotify.EXPIRES_NEVER)
  219.                 else:
  220.                     self.run_config_tool (["--configure-printer",
  221.                                            name, "--no-focus-on-map"])
  222.  
  223.         viewer.notify_new_printer (name, n)
  224.         # Set the icon back how it was.
  225.         self.timeout_ready ()
  226.  
  227.     def run_config_tool (self, argv):
  228.         import os
  229.         pid = os.fork ()
  230.         if pid == 0:
  231.             # Child.
  232.             cmd = "/usr/bin/system-config-printer"
  233.             argv.insert (0, cmd)
  234.             os.execvp (cmd, argv)
  235.             sys.exit (1)
  236.         elif pid == -1:
  237.             print "Error forking process"
  238.         else:
  239.             gobject.timeout_add_seconds (60, self.collect_exit_code, pid)
  240.  
  241.     def print_test_page (self, notification, action, name, devid = ""):
  242.         args = ["--print-test-page", name]
  243.         if devid != "":
  244.             args.extend (["--devid", devid])
  245.         self.run_config_tool (args)
  246.  
  247.     def configure (self, notification, action, name):
  248.         self.run_config_tool (["--configure-printer", name])
  249.  
  250.     def find_driver (self, notification, action, name, devid = ""):
  251.         args = ["--choose-driver", name]
  252.         if devid != "": args = args + ["--devid", devid]
  253.         self.run_config_tool (args)
  254.  
  255.     def setup_printer (self, notification, action, uri, devid = ""):
  256.         args = ["--setup-printer", uri]
  257.         if devid != "": args = args + ["--devid", devid]
  258.         self.run_config_tool (args)
  259.  
  260.     def install_driver (self, notification, action, missing_pkgs):
  261.         try:
  262.             self.packagekit.InstallPackageName (0, 0, missing_pkgs[0])
  263.         except:
  264.             pass
  265.  
  266.     def collect_exit_code (self, pid):
  267.         # We do this with timers instead of signals because we already
  268.         # have gobject imported, but don't (yet) import signal;
  269.         # let's try not to inflate the process size.
  270.         import os
  271.         try:
  272.             print "Waiting for child %d" % pid
  273.             (pid, status) = os.waitpid (pid, os.WNOHANG)
  274.             if pid == 0:
  275.                 # Run this timer again.
  276.                 return True
  277.         except OSError:
  278.             pass
  279.  
  280.         return False
  281.  
  282. PROGRAM_NAME="system-config-printer-applet"
  283. def show_help ():
  284.     print "usage: %s [--no-tray-icon]" % PROGRAM_NAME
  285.  
  286. def show_version ():
  287.     import config
  288.     print "%s %s" % (PROGRAM_NAME, config.VERSION)
  289.     
  290. ####
  291. #### Main program entry
  292. ####
  293.  
  294. global waitloop, runloop, viewer
  295.  
  296. trayicon = True
  297. waitloop = runloop = None
  298. viewer = None
  299.  
  300. if __name__ == '__main__':
  301.     import sys, getopt
  302.     try:
  303.         opts, args = getopt.gnu_getopt (sys.argv[1:], '',
  304.                                         ['no-tray-icon',
  305.                                          'debug',
  306.                                          'help',
  307.                                          'version'])
  308.     except getopt.GetoptError:
  309.         show_help ()
  310.         sys.exit (1)
  311.  
  312.     for opt, optarg in opts:
  313.         if opt == "--help":
  314.             show_help ()
  315.             sys.exit (0)
  316.         if opt == "--version":
  317.             show_version ()
  318.             sys.exit (0)
  319.         if opt == "--no-tray-icon":
  320.             trayicon = False
  321.         elif opt == "--debug":
  322.             set_debugging (True)
  323.  
  324.     # Must be done before connecting to D-Bus (for some reason).
  325.     if not pynotify.init (PROGRAM_NAME):
  326.         try:
  327.             print >> sys.stderr, ("%s: unable to initialize pynotify" %
  328.                                   PROGRAM_NAME)
  329.         except:
  330.             pass
  331.  
  332.     try:
  333.         bus = dbus.SystemBus()
  334.     except:
  335.         try:
  336.             print >> sys.stderr, ("%s: failed to connect to system D-Bus" %
  337.                                   PROGRAM_NAME)
  338.         finally:
  339.             sys.exit (1)
  340.  
  341.     if trayicon:
  342.         try:
  343.             NewPrinterNotification(bus)
  344.         except:
  345.             try:
  346.                 print >> sys.stderr, ("%s: failed to start "
  347.                                       "NewPrinterNotification service" %
  348.                                       PROGRAM_NAME)
  349.             except:
  350.                 pass
  351.  
  352.         try:
  353.             installdriver.PrinterDriversInstaller(bus)
  354.         except Exception, e:
  355.             try:
  356.                 print >> sys.stderr, ("%s: failed to start "
  357.                                       "PrinterDriversInstaller service: %s" %
  358.                                       (PROGRAM_NAME, e))
  359.             except:
  360.                 pass
  361.  
  362.     if trayicon and get_debugging () == False:
  363.         # Start off just waiting for print jobs.
  364.         def any_jobs ():
  365.             try:
  366.                 c = cups.Connection ()
  367.                 jobs = c.getJobs (my_jobs=True, limit=1)
  368.                 if len (jobs):
  369.                     return True
  370.             except:
  371.                 pass
  372.  
  373.             return False
  374.  
  375.         if not any_jobs ():
  376.  
  377.             ###
  378.             class WaitForJobs:
  379.                 DBUS_PATH="/com/redhat/PrinterSpooler"
  380.                 DBUS_IFACE="com.redhat.PrinterSpooler"
  381.  
  382.                 def __init__ (self, bus, waitloop):
  383.                     self.bus = bus
  384.                     self.waitloop = waitloop
  385.                     self.timer = None
  386.                     bus.add_signal_receiver (self.handle_dbus_signal,
  387.                                              path=self.DBUS_PATH,
  388.                                              dbus_interface=self.DBUS_IFACE)
  389.  
  390.                 def __del__ (self):
  391.                     bus = self.bus
  392.                     bus.remove_signal_receiver (self.handle_dbus_signal,
  393.                                                 path=self.DBUS_PATH,
  394.                                                 dbus_interface=self.DBUS_IFACE)
  395.                     if self.timer:
  396.                         gobject.source_remove (self.timer)
  397.  
  398.                 def handle_dbus_signal (self, *args):
  399.                     if self.timer:
  400.                         gobject.source_remove (self.timer)
  401.                     self.timer = gobject.timeout_add (200, self.check_for_jobs)
  402.  
  403.                 def check_for_jobs (self, *args):
  404.                     debugprint ("checking for jobs")
  405.                     if any_jobs ():
  406.                         gobject.source_remove (self.timer)
  407.                         self.waitloop.quit ()
  408.  
  409.                     # Don't run this timer again.
  410.                     return False
  411.             ###
  412.  
  413.             waitloop = gobject.MainLoop ()
  414.             jobwaiter = WaitForJobs(bus, waitloop)
  415.             waitloop.run()
  416.             del jobwaiter
  417.             waitloop = None
  418.  
  419.     if viewer == None:
  420.         import jobviewer
  421.         import gtk
  422.         runloop = gobject.MainLoop ()
  423.         gtk.window_set_default_icon_name ('printer')
  424.         viewer = jobviewer.JobViewer(bus=bus, loop=runloop,
  425.                                      trayicon=trayicon)
  426.  
  427.     try:
  428.         runloop.run()
  429.     except KeyboardInterrupt:
  430.         pass
  431.     viewer.cleanup ()
  432.